#!/usr/bin/python
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Script to generate byte array constants of one or more data resource files.

This is used to embed resource files into static libraries, similar to how
Java resources are stored in jar files.
Usage:
  $ gen_resource_source.py [-h] [-sourcepath <path>] [-o output_file]
      [-link_class <name>] <files>
"""

import argparse
import functools
import os
import subprocess
import sys

# Used by argparse to build help string.
USAGE_STRING = """
Generates a C source file that declares byte array and array length
constants for one or more data resource files. These constants are
combined into a named data segment used to support the getResource()
and getResourceAsStream() methods in IOSClass.
"""

HEADER_COMMENT = """//
// Generated by gen_resource_source.py
//

"""

LINK_CLASS_TEMPLATE = """
@interface {} : NSObject
@end
@implementation {}
@end
"""


def ProcessResourceFile(resource_path, output_file):
  """Appends the embedded version of the resource to file.

  This function generates a static byte array for the resource, then a
  J2OBJC_RESOURCE macro which describes it.

  Args:
      resource_path: the path to the resource file, which is used to generate a
        resource name that matches the path Class.getResource() uses to find a
        Java resource.
      output_file: the file that is updated with the embedded data.
  """
  array_name = resource_path.replace("/", "_").replace(".", "_").replace(
      "-", "_")
  if array_name[0] != "_":
    array_name = "_" + array_name
  array_name_hash = "0x{:02x}".format(hash(array_name) & (2**32 - 1))
  output_file.write("\nstatic jbyte {}[] = {{".format(array_name))
  length = 0
  file_path = os.path.join(args.sourcepath, resource_path)
  with open(file_path, "rb") as in_file:
    for byte in iter(functools.partial(in_file.read, 1), b""):
      if length % 10 == 0:
        output_file.write("\n ")
      output_file.write(" 0x%02X," % ord(byte))
      length += 1
  output_file.write("\n};\n")
  output_file.write("J2OBJC_RESOURCE(\\\n  {}, \\\n  {}, \\\n  {});\n".format(
      array_name, length, array_name_hash))


if __name__ == "__main__":

  parser = argparse.ArgumentParser(description=USAGE_STRING)
  parser.add_argument(
      "-sourcepath",
      metavar="<path>",
      default=".",
      help="specify root directory for resource files")
  parser.add_argument(
      "-o",
      required=True,
      metavar="output_file",
      help="the output file to create")
  parser.add_argument(
      "-link_class",
      metavar="<name>",
      help="name of empty Objective C class to generate")
  parser.add_argument(
      "files", help="resource data files", nargs=argparse.REMAINDER)
  if len(sys.argv) == 1:
    parser.print_help(sys.stderr)
    sys.exit(1)
  args = parser.parse_args()
  out = open(args.o, "w")
  out.write(HEADER_COMMENT)
  out.write("#include \"J2ObjC_source.h\"\n")
  for rf in args.files:
    ProcessResourceFile(rf, out)

  if args.link_class:
    out.write(LINK_CLASS_TEMPLATE.format(args.link_class, args.link_class))

  out.write(
    "\n// Resources checksums (run \"openssl sha256 <file>\" "
    + "to verify)\n//\n"
  )
  os.chdir(args.sourcepath)
  checksums = subprocess.check_output(["openssl", "sha256"] +
                                      args.files).splitlines()
  for checksum in checksums:
    parts = checksum.split("=")
    out.write("// {}\n".format(parts[0]))
    out.write("//  {}\n".format(parts[1]))
  out.close()
